Sparse atlases¶
This demo showcases the INIA19 template and atlas for the rhesus monkey. The INIA19 atlas is sparse, containing hundreds of regions distributed across thousands of indices. NiiVue efficiently visualizes this type of atlas using minimal resources, ensuring smooth interactivity even on low-power devices.
This Python script is similar the corresponding JavaScript web demo
In [1]:
from pathlib import Path
from ipyniivue import download_dataset
BASE_API_URL = "https://niivue.com/demos/images/"
DATA_FOLDER = Path("images")
# Download data for example
download_dataset(
BASE_API_URL,
dest_folder=DATA_FOLDER,
files=[
"inia19-t1-brain.nii.gz",
"inia19-NeuroMaps.nii.gz",
"inia19-NeuroMaps.json",
],
)
inia19-t1-brain.nii.gz already exists. inia19-NeuroMaps.nii.gz already exists. inia19-NeuroMaps.json already exists. Dataset downloaded successfully to images.
In [2]:
import json
import ipywidgets as widgets
from IPython.display import display
from ipyniivue import DragMode, NiiVue, ShowRender
# Setup NiiVue Instance
nv = NiiVue(
back_color=(0.5, 0.5, 0.5, 1),
show_3d_crosshair=True,
drag_mode=DragMode.PAN,
yoke_3d_to_2d_zoom=True,
multiplanar_show_render=ShowRender.ALWAYS,
)
nv.load_volumes(
[
{"path": DATA_FOLDER / "inia19-t1-brain.nii.gz"},
{"path": DATA_FOLDER / "inia19-NeuroMaps.nii.gz", "opacity": 0.5},
]
)
# for urls: nv.volumes[1].set_colormap_label_from_url("./images/inia19-NeuroMaps.json")
with open(DATA_FOLDER / "inia19-NeuroMaps.json") as f:
cmap = json.load(f)
nv.volumes[1].set_colormap_label(cmap)
nv.volumes[1].opacity = 0.03
nv.set_atlas_outline(0.01)
## UI
# Slider for opacity
opacity_slider = widgets.IntSlider(
min=1,
max=255,
value=8,
description="Opacity",
continuous_update=True,
readout=False,
)
location_label = widgets.HTML(" ")
outline_options = ["None", "Gap", "Opaque", "Black"]
outline_dropdown = widgets.Dropdown(
options=outline_options,
value="Gap",
description="Atlas outline",
)
render_options = ["Slices", "Matte", "Low", "Medium", "High"]
render_dropdown = widgets.Dropdown(
options=render_options,
value="Matte",
description="Render mode",
style={"description_width": "initial"},
)
## Define callbacks
def on_opacity_change(change):
"""Update the opacity of the atlas volume."""
nv.volumes[1].opacity = change["new"] / 255
def on_outline_change(change):
"""Set atlas outline style."""
value_name = change["new"]
# Default borderValue for "No border"
borderValue = 0.0
if value_name == "Gap":
borderValue = 0.01
elif value_name == "Opaque":
borderValue = 1
elif value_name == "Black":
borderValue = -1.0
# else "None" → 0.0
nv.set_atlas_outline(borderValue)
def on_render_change(change):
"""Set render mode."""
value_name = change["new"]
# Default borderValue for "matte"
renderValue = 0.0
if value_name == "Slices":
renderValue = -1.0
elif value_name == "Low":
renderValue = 0.3
elif value_name == "Medium":
renderValue = 0.6
elif value_name == "High":
renderValue = 1.0
# else "Matte" → 0.0
nv.set_volume_render_illumination(renderValue)
nv.update_gl_volume()
def handle_location_change(location):
"""Update the location label with current coordinates."""
region = int(location["values"][1]["value"])
if region == nv.opts.atlas_active_index:
return
nv.set_atlas_active_index(region)
location_label.value = location["string"]
## Setup observers
opacity_slider.observe(on_opacity_change, names="value")
nv.on_location_change(handle_location_change)
on_opacity_change({"new": opacity_slider.value})
outline_dropdown.observe(on_outline_change, names="value")
render_dropdown.observe(on_render_change, names="value")
## Display All
controls = widgets.HBox([opacity_slider, outline_dropdown, render_dropdown])
display(
widgets.VBox(
[
controls,
nv,
location_label,
]
)
)